#include <iostream>
#include "Thread.hpp"
#include "LockGuard.hpp"
#include "Log.hpp"
#include <string>
#include <queue>
#include <vector>
using namespace log_ns;
using namespace ThreadMoudle;
static const int gdefaultnum = 5;
void test()
{
  while (true)
  {
    std::cout << "hello,word" << std::endl;
    sleep(1);
  }
}
template <typename T>
class ThreadPool
{
private:
  void LockQueue()
  {
    pthread_mutex_lock(&_mutex);
  }
  void UnlockQueue()
  {
    pthread_mutex_unlock(&_mutex);
  }
  void Wakeup()
  {
    pthread_cond_signal(&_cond);
  }
  void WakeupAll()
  {
    pthread_cond_broadcast(&_cond);
  }
  void Sleep()
  {
    pthread_cond_wait(&_cond, &_mutex);
  }
  bool IsEmpty()
  {
    return _task_queue.empty();
  }
  void HandlerTask(const std::string &name) // 这里函数内部自己包含一个参数this指针
  {
    while (true)
    {
      LockQueue();

      while (IsEmpty() && _isrunning)
      {

        _sleep_thread_num++;
        LOG(INFO,"%sthread sleep begin!\n",name.c_str());
        Sleep();
        LOG(INFO,"%sthread wakeup!\n",name.c_str());
        _sleep_thread_num--;
      }
      if (IsEmpty() && !_isrunning) // 这里的任务是否为空的优先级最高不为空就一直运行直到为空并终止；就算有只但是要退出还是不退直到任务做完
      {
        std::cout << name << "quit" << std::endl;
        UnlockQueue();
        LOG(INFO,"%sthread quit begin!\n",name.c_str());

        break;
      }
      // 做任务
      T t = _task_queue.front();
      _task_queue.pop();
      UnlockQueue();
      // 处理任务
      t();
      // std::cout << name << ":" << t.result() << std::endl;
      // LOG(DEBUG,"hander task done,task is :%s \n ",t.result().c_str());
    }
  }
  ThreadPool(int thread_num = gdefaultnum) : _thread_num(thread_num), _isrunning(false), _sleep_thread_num(0)
  {
    _task_queue = {};
    std::cout << IsEmpty() << std::endl;
    std::cout << _task_queue.empty() << std::endl;
    pthread_mutex_init(&_mutex, nullptr);
    pthread_cond_init(&_cond, nullptr);
  }
  ThreadPool(const ThreadPool<T> &)=delete;
  void operator =(const ThreadPool <T> &)=delete;

public:

  void Init()                                                                       // 这个是初始化问题的
  {                                                                                 // 这里最后的参数是一个占位符这里就可以将上面的函数的参数改为无参数函数
    func_t func = std::bind(&ThreadPool::HandlerTask, this, std::placeholders::_1); // 这里将函数ThreadPool函数的this指针和函数名绑定这里的func的函数就是一个无参数的函数；
    //  func_t func = std::bind(&ThreadPool::HandlerTask, this);
    for (int i = 0; i < _thread_num; i++)
    {
      std::string _threadname = "thread-" + std::to_string(i + 1);
      _threads.emplace_back(_threadname, func);
      LOG(DEBUG,"construct thread %s done init success\n",_threadname.c_str());
    }
  }
  void Start() // 开启线程
  {
    _isrunning = true;
    for (auto &thread : _threads)
    {
      LOG(DEBUG,"start thread %s done .\n",thread.Name().c_str());
      thread.Start();
      sleep(1);
    }
  }
  void Stop()
  {
    LockQueue();
    WakeupAll();
    _isrunning = false;
    UnlockQueue();
    LOG(INFO,"Thread Pool Stop Sucess!\n");
  }
  static ThreadPool<T>*GetInstance()//懒汉模式单例线程安全的版本
  {
    if(_tp==nullptr)
    {
    LockGuard lockguard(&_sig_mutex);
    if(_tp==nullptr)
    {
      LOG(INFO ,"create threadpool \n");
      _tp=new ThreadPool();
      _tp->Init();
      _tp->Start();
    }
    else
    {
      LOG(INFO,"get threadpool\n");
    }
    }
    return _tp;

  }
  void Equeue(const T &in) // 插入数据
  {
    LockQueue();
    if (_isrunning)
    {
      _task_queue.push(in);
      if (_sleep_thread_num)
      {
        Wakeup();
      }
    }

    UnlockQueue();
  }
  ~ThreadPool()
  {
    pthread_mutex_destroy(&_mutex);
    pthread_cond_destroy(&_cond);
  }

private:
  int _thread_num;
  std::vector<Thread> _threads; // 内存池右边的线程
  std::queue<T> _task_queue;    // 内存池左边的队列
  bool _isrunning;
  int _sleep_thread_num;
  pthread_mutex_t _mutex;
  pthread_cond_t _cond;
  //单例模式
  static ThreadPool<T>*_tp;
  static pthread_mutex_t _sig_mutex;
};
template<typename T>
ThreadPool<T>*ThreadPool<T>::_tp=nullptr;
template<typename T>
pthread_mutex_t ThreadPool<T>::_sig_mutex=PTHREAD_MUTEX_INITIALIZER;